package lpca.utils 
{  
	import Array;
    import flash.utils.ByteArray; 
	import Math;
	import flash.display.*;
	import lpca.utils.Matrix;
	import lpca.utils.Point;
 
    /** 
	 * 
	 * @author figishe@gmail.com
	*/
	public class Maze implements IMaze
	{	
		public static const DIR_LEFT: int = 3; 
		public static const DIR_RIGHT: int = 1;
		public static const DIR_DOWN: int = 2;
		public static const DIR_UP: int = 0;
		
		public function getMaxDirection(): int 
		{ 
			return DIR_LEFT;
		}
		
		public function getMinDirection(): int 
		{ 
			return DIR_UP; 
		}
		
		public function getNextDirection(dir: int): int
		{
			if (dir < DIR_LEFT)
				return ++dir;
			else	
			{
				if (dir == DIR_LEFT)
					return DIR_UP;
				else
					throw 'В getNextDirection передано недопустимое направление.'; // поменять на что-то из класса Error? не?
			}
		}
		
		protected var map: Array = [];	// матрица ячеек
		
		private var sizeX: int;
		private var sizeY: int; // размеры матрицы ячеек
		
		private var startPoint: Point;	
		private var finishPoint: Point;	
		
		
		public function Maze(sizeX: int = 100, sizeY: int = 100) // конструктор, создает пустой массив строк (двумерный массив ячеек)
		{
			this.map = new Array(); 
			for (var y: int = 0; y <= sizeY+1; y++ ) // создаем массивы строк от 0 до sizeY+1 (0 и sizeY+1 строки для обозначения границ)
				this.map[y] = new Array();
			this.sizeX = sizeX;
			this.sizeY = sizeY;
			
			this.startPoint = null;
			this.finishPoint = null;
		}
		
		public function getSizeX(): int { return this.sizeX }
		public function getSizeY(): int { return this.sizeY }
		
		public function getStartPoint(): Point { return this.startPoint }
		public function getFinishPoint(): Point { return this.finishPoint }
		
		public function setStartPoint(point: Point): void
		{
			if (point != null)
			{
				if (this.startPoint != null)
				{
					setCell(this.startPoint, new Cell(Cell.CELL_EMPTY));
				}
				this.startPoint = point;
				setCell(this.startPoint, new Cell(Cell.CELL_START)); //очищаем старую точку старта
				trace('Точка старта установлена в (', point.x, ';', point.y, ')');
			}
		}
		
		public function setFinishPoint(point: Point): void 
		{
			if (point != null)
			{
				if (this.finishPoint != null)
				{
					setCell(this.finishPoint, new Cell(Cell.CELL_EMPTY)); // очищаем старую точку финиша
					trace('Удалена точка финиша (', this.finishPoint.x, ';', this.finishPoint.y, ')');
				}
				this.finishPoint = point;
				setCell(this.finishPoint, new Cell(Cell.CELL_FINISH));
				trace('Точка финиша установлена в (', point.x, ';', point.y, ')');
			}
		}
		
		public function setCell(point: Point,  cell: Cell): void 
		{
			if ((point != null) && (cell != null) && (sizeX >= point.x) && (sizeY >= point.y)) 
				//this.map[point.y][point.x] = cell; // FIXME:  Error #1010: Термин не определен и не имеет свойств.
				this.map[point.y][point.x] = cell.clone();
			else
			{
				trace('Клетка не установлена!');
				if (point == null) trace('Причина: point == null');
				if (cell == null) trace('Причина: cell == null');
				//if (getCell(point) == null) trace('Причина: точка выходит за границы карты');
				if ((sizeX >= point.x) || (sizeY >= point.y)) trace('Причина: точка выходит за границы карты');
			}
		}
		
		public function getCell(point: Point): Cell
		{
			if ((point.x > 0) && (point.x <= sizeX) && (point.y > 0) && (point.y <= sizeY))
				return (this.map[point.y][point.x] as Cell).clone();
			else 
				return null;
		}	
		
		public function getNearestCell(point: Point, direction: int): Cell
		{
			return(getCell(point.next(direction)));
		}
				
		
		public function fillWith(cell: Cell): void
		{
			for (var x: int = 1; x <= sizeX; x++)
				for (var y: int = 1; y <= sizeY; y++)
				{
					setCell(new Point(x, y), cell);
				}
		}
		
		public static function mirroredDirection(direction: int): int
		{
			// FIXME: убрать break?
			switch(direction)
			{
				case DIR_DOWN:
					return DIR_UP;
					break;
				case DIR_UP:
					return DIR_DOWN;
					break;
				case DIR_LEFT:
					return DIR_RIGHT;
					break;
				case DIR_RIGHT:
					return DIR_LEFT;
					break;
				default: 
					return -1; // оп-па!
			}
		}
		
		public function insertMatrix(x0: int, y0: int, m: Matrix): void
		{
			for (var x: int = 0; x < m.sizeX; x++)
				for (var y: int = 0; y < m.sizeY; y++)
				{
					setCell(new Point(x0 + x, y0 + y), new Cell(m.val(x, y)));
				}
		}
		
		public function show():void
		{
			for (var y:int = 1; y <= sizeY; y++)
				{
					var sValues: String = '';
					for (var x:int = 1; x <= sizeX; x++)
					{
						switch (map[y][x].value)
						{
							case Cell.CELL_WALL: 
								sValues += '█'; // символ для вывода стен
								break;
							case Cell.CELL_EMPTY:
								sValues += ' '; // символ для вывода пустых клеток
								break;
							case Cell.CELL_START:
								sValues += 'S'; // символ для вывода стартовой позиции
								break;
							case Cell.CELL_FINISH:
								sValues += 'F'; // символ для вывода стартовой позиции
								break;
							//case Cell.CELL_WAY:
								//sValues += ':'; // символ для вывода стартовой позиции
								//break;
							default:
								sValues += '?';
								break;
						}
					}
					trace(sValues);
					sValues = '';
				}
		}
		
		/*
		public function printZaputannost(): void
		{
			trace(1 / Math.abs(Math.sqrt(startPoint.x*startPoint.x + startPoint.y*startPoint.y) - Math.sqrt(finishPoint.x*finishPoint.x + finishPoint.y*finishPoint.y)));
		}
		*/
		
		public function showGraphics(movieClip: MovieClip, scaleX: int, scaleY: int):void
		{
			for (var y:int = 1; y <= sizeY; y++)
				{
					for (var x:int = 1; x <= sizeX; x++)
					{
						switch (map[y][x].value)
						{
							case Cell.CELL_WALL: 
								movieClip.graphics.beginFill(0x000000);
								movieClip.graphics.drawRect(x * scaleX, y * scaleY, x * (scaleX + 1), y * (scaleY + 1));
								movieClip.graphics.endFill();
								break;
							case Cell.CELL_EMPTY:
								movieClip.graphics.beginFill(0xCCCCCC);
								movieClip.graphics.drawRect(x * scaleX, y * scaleY, x * (scaleX + 1), y * (scaleY + 1));
								movieClip.graphics.endFill();
								break;
							case Cell.CELL_START:
								movieClip.graphics.beginFill(0xFFCC00);
								movieClip.graphics.drawRect(x * scaleX, y * scaleY, x * (scaleX + 1), y * (scaleY + 1));
								movieClip.graphics.endFill();
								break;
							case Cell.CELL_FINISH:
								movieClip.graphics.beginFill(0x00BFFF);
								movieClip.graphics.drawRect(x * scaleX, y * scaleY, x * (scaleX + 1), y * (scaleY + 1));
								movieClip.graphics.endFill();
								break;
							//case Cell.CELL_WAY:
								//movieClip.graphics.beginFill(0xEEEEEE);
								//movieClip.graphics.drawRect((x * scaleX), (y * scaleY), (x * (scaleX + 1)), (y * (scaleY + 1)));
								//movieClip.graphics.endFill();
								break;
							default:
								//movieClip.graphics.drawRect(x*dx, y*dy, x*(dx+1), y*(dx+1));
								break;
						}
					}
					movieClip.x = 0;
					movieClip.y = 0;
				}
		}
	}		

}